/* lex */

#include "blex.h"
#include "bconf.h"

#include <string.h>

char *reserved[] = {"mov", "add", "set", "read", "write", "loop",
                    "end","int","char"};

void bf_lexerror(LState* l, char* errordat) {
	l->errors++;
	bf_error(errordat);
}

void initLState(LState* l, IGT* i) {
	if(i == NULL) return;
	l->i = i;
	l->errors = 0;
	l->current = '\n';
	l->linenum = 0;
}


Token_t matchtoken(char* str) {
	int i;
	for (i=0; i<(sizeof(reserved)/sizeof(reserved[0])); i++) {
		if(!strcmp(str, reserved[i])) {
			return (Token_t)(i+1);
		}
	}
	return ERR;
}

Tokendata lex(LState* l) {
	while(1) {
		int sgn = 1;	/* for numbers */
		switch(curr(l)) {
			case ' ':
			case '\t': {
				next(l);
				break;
			}
			case '\n': {
				l->linenum++;
				next(l);
				break;
			}
			case '#': {
				while(curr(l) != '\n' && curr(l) != EOI) {
					next(l);
				}
				if(curr(l) == EOI) {
					return tok2dat(EOS, 0);
				}
				break;
			}
			case EOI: {
				return tok2dat(EOS, 0);
				break;
			}
			case '-':
				sgn = -1;	/* no break */
			case '+':
				next(l);
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9': {
				int a = 0;
				while(curr(l) >= '0' && curr(l) <= '9') {
					a = (a << 3) + (a << 1) + curr(l) - '0';
					next(l);
				}
				if(notsep(curr(l))) {
					char errorbuff[40];
					sprintf(errorbuff,"Error: Non-empty char after a number "
					        "in line %d.\n", l->linenum);
					bf_lexerror(l, errorbuff);
				}
				return tok2dat(NUM, a * sgn);
				break;
			}
			default: {
				char buff[MAXNAMELEN + 1];		/* +1 for \0 */
				int pos;
				for(pos = 0; notsep(curr(l)) && pos < MAXNAMELEN; pos++) {
					buff[pos] = curr(l);
					next(l);
				}
				if(pos == MAXNAMELEN && notsep(curr(l))) {
					char errorbuff[40];
					sprintf(errorbuff,"Error: sequence too long "
					        "in line %d.\n", l->linenum);
					bf_lexerror(l, errorbuff);
				}
				buff[pos] = '\0';
				/* panic */
				while(notsep(curr(l))) {
					next(l);
				}
				Token_t t = matchtoken(buff);
				if(t == ERR) {
					char errorbuff[70];
					sprintf(errorbuff,"Error: unknown sequence (\"%s\") "
					        "in line %d.\n",buff , l->linenum);
					bf_lexerror(l, errorbuff);
					next(l);
				} else
					/* ADD and MOV return 1 for field extra */
					return tok2dat(t, t <= ADD);
				break;
			}
		}
	}
}
